#pragma once 

#include<iostream>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<unistd.h>

const int default_size = 4096;
int proj_id = 0x66;
std::string path_name = ".";

class SharedMemory
{
private:
    bool _Create(int flags)
    {
        _key = ftok(path_name.c_str(), proj_id);
        if(_key < 0)
        {
            perror("ftok");
            return false;
        }
        printf("key = %x\n", _key);
        _shmid = shmget(_key, _size, flags);
        if(_shmid < 0)
        {
            perror("shmget");
            return false;
        }
        printf("shmid = %x\n", _shmid);
        return true; 
    }
public:
    SharedMemory(int size = default_size)
        :_size(size)
        ,_key(0)
        ,_shmid(-1)
        ,_start_addr(nullptr)
        ,_data_start(nullptr)
        ,_num(nullptr)
        ,_windex(0)
        ,_rindex(0)
    {}
    
    bool Create()
    {
        return _Create(IPC_CREAT | IPC_EXCL | 0666);
    }

    bool Get()
    {
        return _Create(IPC_EXCL);
    }

    bool Remove()
    {
        int ret = shmctl(_shmid, IPC_RMID, nullptr);
        if(ret < 0)
        {
            perror("shmctl");
            return false;
        }
        std::cout << "删除成功" << std::endl;
        return true;
    }

    bool Attach()
    {
        _start_addr = shmat(_shmid, nullptr, 0);
        if((long long)_start_addr < 0)
        {
            perror("shmat");
            return false;
        }
        std::cout << "挂载成功" << std::endl;
        _num = (int*)_start_addr;
        _data_start = (char*)_start_addr + sizeof(int);
        *_num = 0;
        return true;
    }

    void AddChar(char x)
    {
        // if(*_num == _size)
        // {
        //     return;
        // }
        _data_start[_windex++] = x;
        _data_start[_windex] = '\0';
        std::cout << x << std::endl;
        _windex %= _size;
        *(_num)++;
    }

    void PopChar(char* x)
    {
        // if(*_num == 0)
        // {
        //     return;
        // }
        *x = _data_start[_rindex++];
        _rindex %= _size;
        *(_num)--;
        printf("%s\n", _data_start);
    }

    bool Detach()
    {
        int ret = shmdt(_start_addr);
        if(ret < 0)
        {
            perror("shmdt");
            return false;
        }
        std::cout << "移除挂载成功" << std::endl;
        return true;
    }

    void Print()
    {
        struct shmid_ds ds;
        int ret = shmctl(_shmid, IPC_STAT, &ds);
        printf("key: %x\n", ds.shm_perm.__key);
        printf("size: %ld\n", ds.shm_segsz);
        printf("nattach: %ld\n", ds.shm_nattch);
    }

private:
    int _size;
    key_t _key;
    int _shmid;
    void* _start_addr;
    char* _data_start;
    int* _num;
    int _windex;
    int _rindex;
};